package cz.data.domain.elasticsearch.service;

import cz.data.common.base.BaseResponse;
import cz.data.common.elastic.ElasticSearchUtils;
import cz.data.common.support.db.DbProperty;
import cz.data.common.support.db.core.DbColumn;
import cz.data.common.support.db.core.DbTable;
import cz.data.common.support.db.driver.TableOperation;
import cz.data.common.support.db.manage.DbManage;
import cz.data.common.support.db.manage.DbManageFactory;
import cz.data.common.support.db.manage.DbManageRegistry;
import cz.data.common.utils.ThrowableUtil;
import cz.data.domain.metadata.model.MetadataUtil;
import cz.data.domain.metadata.model.entity.MetadataSourceEntity;
import cz.data.domain.metadata.rpc.MetadataFeign;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

@Component
public class ElasticsearchMetadataService {
    @Resource
    MetadataFeign metadataFeign;

    public BaseResponse connect(DbProperty property) {
        RestHighLevelClient client = null;
        try {
            client = ElasticSearchUtils.createClient(property);
            client.info(RequestOptions.DEFAULT);
            return BaseResponse.success();
        } catch (IOException e) {
            return BaseResponse.error(500, e.getMessage());
        } finally {
            if (Objects.nonNull(client)) {
                ThrowableUtil.throwable(client::close, false);
            }
        }
    }

    public boolean createTable(TableOperation operation) {
        MetadataSourceEntity source = metadataFeign.getMetadataSourceById(operation.getSourceId());
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.createTable(operation.getTable(), operation.getProperties());
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }

    public boolean dropTable(TableOperation operation) {
        MetadataSourceEntity source = metadataFeign.getMetadataSourceById(operation.getSourceId());
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.deleteTable(operation.getTable());
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }

    public List<DbTable> getSourceAllTable(String sourceId) {
        return getSourceAllTable(metadataFeign.getMetadataSourceById(sourceId));
    }

    public List<DbTable> getSourceAllTable(MetadataSourceEntity source) {
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.getTables(property.getDbName(), property.getSchemaName());
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }

    public List<DbColumn> getSourceTableColumns(String sourceId, String tableName) {
        MetadataSourceEntity source = metadataFeign.getMetadataSourceById(sourceId);
        return getSourceTableColumns(source, tableName);
    }

    public List<DbColumn> getSourceTableColumns(MetadataSourceEntity source, String tableName) {
        DbProperty property = MetadataUtil.dbProperty(source);
        DbManage dbManage = null;
        try {
            DbManageFactory factory = DbManageRegistry.factory(property.getDbTypeEnum());
            dbManage = factory.factory(property);
            return dbManage.getTableColumns(property.getDbName(), property.getSchemaName(), tableName);
        } finally {
            if (Objects.nonNull(dbManage)) {
                ThrowableUtil.throwable(dbManage::close);
            }
        }
    }
}
